/*
 * SOURCE:  http://www.aarongifford.com/computers/sha.html
 * FILE:    http://www.aarongifford.com/computers/hmac_sha1.tar.gz
 * DATE:    27 June 2008
 * LICENCE: Public Domain (sha1.c)
 * LICENCE: BSD (hmac_sha1.c)
 *
 * Modified to add const specifiers and the SHA1() and HMAC_SHA1()
 * convenience functions.
 */

/*
 * sha1.c
 *
 * Originally witten by Steve Reid <steve@edmweb.com>
 * 
 * Modified by Aaron D. Gifford <agifford@infowest.com>
 *
 * NO COPYRIGHT - THIS IS 100% IN THE PUBLIC DOMAIN
 *
 * The original unmodified version is available at:
 *    ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* #include "hmac_sha1.h" */
#include "sha1.h"
#include <string.h>
#include <assert.h>

#ifdef  __cplusplus
extern "C" {
#endif

#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */

#ifdef LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&(sha1_quadbyte)0xFF00FF00) \
	|(rol(block->l[i],8)&(sha1_quadbyte)0x00FF00FF))
#else
#define blk0(i) block->l[i]
#endif

#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
	^block->l[(i+2)&15]^block->l[i&15],1))

/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);

typedef union _BYTE64QUAD16 {
	sha1_byte c[64];
	sha1_quadbyte l[16];
} BYTE64QUAD16;

/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1_Transform(sha1_quadbyte state[5], const sha1_byte buffer[64]) {
	sha1_quadbyte	a, b, c, d, e;
	BYTE64QUAD16	*block;

	block = (BYTE64QUAD16*)buffer;
	/* Copy context->state[] to working vars */
	a = state[0];
	b = state[1];
	c = state[2];
	d = state[3];
	e = state[4];
	/* 4 rounds of 20 operations each. Loop unrolled. */
	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
	/* Add the working vars back into context.state[] */
	state[0] += a;
	state[1] += b;
	state[2] += c;
	state[3] += d;
	state[4] += e;
	/* Wipe variables */
	a = b = c = d = e = 0;
}


/* SHA1_Init - Initialize new context */
void SHA1_Init(SHA_CTX* context) {
    assert(sizeof(sha1_quadbyte) == 4);
    assert(sizeof(sha1_byte)     == 1);

	/* SHA1 initialization constants */
	context->state[0] = 0x67452301;
	context->state[1] = 0xEFCDAB89;
	context->state[2] = 0x98BADCFE;
	context->state[3] = 0x10325476;
	context->state[4] = 0xC3D2E1F0;
	context->count[0] = context->count[1] = 0;
}

/* Run your data through this. */
void SHA1_Update(SHA_CTX *context, const sha1_byte *data, unsigned int len) {
	unsigned int	i, j;

	j = (context->count[0] >> 3) & 63;
	if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
	context->count[1] += (len >> 29);
	if ((j + len) > 63) {
	    memcpy(&context->buffer[j], data, (i = 64-j));
	    SHA1_Transform(context->state, context->buffer);
	    for ( ; i + 63 < len; i += 64) {
	        SHA1_Transform(context->state, &data[i]);
	    }
	    j = 0;
	}
	else i = 0;
	memcpy(&context->buffer[j], &data[i], len - i);
}


/* Add padding and return the message digest. */
void SHA1_Final(sha1_byte digest[SHA1_DIGEST_LENGTH], SHA_CTX *context) {
	sha1_quadbyte	i, j;
	sha1_byte	finalcount[8];

	for (i = 0; i < 8; i++) {
	    finalcount[i] = (sha1_byte)((context->count[(i >= 4 ? 0 : 1)]
	     >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
	}
	SHA1_Update(context, (sha1_byte *)"\200", 1);
	while ((context->count[0] & 504) != 448) {
	    SHA1_Update(context, (sha1_byte *)"\0", 1);
	}
	/* Should cause a SHA1_Transform() */
	SHA1_Update(context, finalcount, 8);
	for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
	    digest[i] = (sha1_byte)
	     ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
	}
	/* Wipe variables */
	i = j = 0;
	memset(context->buffer, 0, SHA1_BLOCK_LENGTH);
	memset(context->state, 0, SHA1_DIGEST_LENGTH);
	memset(context->count, 0, 8);
	memset(&finalcount, 0, 8);
}

void SHA1(sha1_byte digest[SHA1_DIGEST_LENGTH], const sha1_byte *data, unsigned int len) {
    SHA_CTX ctx;
    SHA1_Init(&ctx);
    SHA1_Update(&ctx, data, len);
    SHA1_Final(digest, &ctx);
}


/*
 * hmac_sha1.c
 *
 * Version 1.0.0
 *
 * Written by Aaron D. Gifford <me@aarongifford.com>
 *
 * Copyright 1998, 2000 Aaron D. Gifford.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * The HMAC-SHA1 has is defined as:
 *
 *     HMAC = SHA1(K XOR opad, SHA1(K XOR ipad, message))
 *
 * "opad" is 64 bytes filled with 0x5c
 * "ipad" is 64 bytes filled with 0x36
 * "K" is the key material
 *
 * If the key material "K" is longer than 64 bytes, then the key material
 * will first be digested (K = SHA1(K)) resulting in a 20-byte hash.
 * If the key material is shorter than 64 bytes, it is padded with zero
 * bytes.
 *
 * This code precomputes "K XOR ipad" and "K XOR opad" since that just makes
 * sense.
 *
 * This code was heavily influenced by Eric A. Young's in how the interface
 * was designed and how this file is formatted.
 */

/* Filler bytes: */
#define IPAD_BYTE	0x36
#define OPAD_BYTE	0x5c
#define ZERO_BYTE	0x00

void HMAC_SHA1_Init(HMAC_SHA1_CTX *ctx) {
	memset(&(ctx->key[0]), ZERO_BYTE, HMAC_SHA1_BLOCK_LENGTH);
	memset(&(ctx->ipad[0]), IPAD_BYTE, HMAC_SHA1_BLOCK_LENGTH);
	memset(&(ctx->opad[0]), OPAD_BYTE, HMAC_SHA1_BLOCK_LENGTH);
	ctx->keylen = 0;
	ctx->hashkey = 0;
}

void HMAC_SHA1_UpdateKey(HMAC_SHA1_CTX *ctx, const unsigned char *key, unsigned int keylen) {

	/* Do we have anything to work with?  If not, return right away. */
	if (keylen < 1)
		return;

	/*
	 * Is the total key length (current data and any previous data)
	 * longer than the hash block length?
	 */
	if (ctx->hashkey !=0 || (keylen + ctx->keylen) > HMAC_SHA1_BLOCK_LENGTH) {
		/*
		 * Looks like the key data exceeds the hash block length,
		 * so that means we use a hash of the key as the key data
		 * instead.
		 */
		if (ctx->hashkey == 0) {
			/*
			 * Ah, we haven't started hashing the key
			 * data yet, so we must init. the hash
			 * monster to begin feeding it.
			 */

			/* Set the hash key flag to true (non-zero) */
			ctx->hashkey = 1;

			/* Init. the hash beastie... */
			SHA1_Init(&ctx->shactx);

			/* If there's any previous key data, use it */
			if (ctx->keylen > 0) {
				SHA1_Update(&ctx->shactx, &(ctx->key[0]), ctx->keylen);
			}

			/*
			 * Reset the key length to the future true
			 * key length, HMAC_SHA1_DIGEST_LENGTH
			 */
			ctx->keylen = HMAC_SHA1_DIGEST_LENGTH;
		}
		/* Now feed the latest key data to the has monster */
		SHA1_Update(&ctx->shactx, key, keylen);
	} else {
		/*
		 * Key data length hasn't yet exceeded the hash
		 * block length (HMAC_SHA1_BLOCK_LENGTH), so theres
		 * no need to hash the key data (yet).  Copy it
		 * into the key buffer.
		 */
		memcpy(&(ctx->key[ctx->keylen]), key, keylen);
		ctx->keylen += keylen;
	}
}

void HMAC_SHA1_EndKey(HMAC_SHA1_CTX *ctx) {
	unsigned char	*ipad, *opad, *key;
	unsigned int	i;

	/* Did we end up hashing the key? */
	if (ctx->hashkey) {
		memset(&(ctx->key[0]), ZERO_BYTE, HMAC_SHA1_BLOCK_LENGTH);
		/* Yes, so finish up and copy the key data */
		SHA1_Final(&(ctx->key[0]), &ctx->shactx);
		/* ctx->keylen was already set correctly */
	}
	/* Pad the key if necessary with zero bytes */
	if ((i = HMAC_SHA1_BLOCK_LENGTH - ctx->keylen) > 0) {
		memset(&(ctx->key[ctx->keylen]), ZERO_BYTE, i);
	}

	ipad = &(ctx->ipad[0]);
	opad = &(ctx->opad[0]);

	/* Precompute the respective pads XORed with the key */
	key = &(ctx->key[0]);
	for (i = 0; i < ctx->keylen; i++, key++) {
		/* XOR the key byte with the appropriate pad filler byte */
		*ipad++ ^= *key;
		*opad++ ^= *key;
	}
}

void HMAC_SHA1_StartMessage(HMAC_SHA1_CTX *ctx) {
	SHA1_Init(&ctx->shactx);
	SHA1_Update(&ctx->shactx, &(ctx->ipad[0]), HMAC_SHA1_BLOCK_LENGTH);
}

void HMAC_SHA1_UpdateMessage(HMAC_SHA1_CTX *ctx, const unsigned char *data, unsigned int datalen) {
	SHA1_Update(&ctx->shactx, data, datalen);
}

void HMAC_SHA1_EndMessage(unsigned char *out, HMAC_SHA1_CTX *ctx) {
	unsigned char	buf[HMAC_SHA1_DIGEST_LENGTH];
	SHA_CTX		*c = &ctx->shactx;

	SHA1_Final(&(buf[0]), c);
	SHA1_Init(c);
	SHA1_Update(c, &(ctx->opad[0]), HMAC_SHA1_BLOCK_LENGTH);
	SHA1_Update(c, buf, HMAC_SHA1_DIGEST_LENGTH);
	SHA1_Final(out, c);
}

void HMAC_SHA1_Done(HMAC_SHA1_CTX *ctx) {
	/* Just to be safe, toast all context data */
	memset(&(ctx->ipad[0]), ZERO_BYTE, HMAC_SHA1_BLOCK_LENGTH);
	memset(&(ctx->ipad[0]), ZERO_BYTE, HMAC_SHA1_BLOCK_LENGTH);
	memset(&(ctx->key[0]), ZERO_BYTE, HMAC_SHA1_BLOCK_LENGTH);
	ctx->keylen = 0;
	ctx->hashkey = 0;
} 

void HMAC_SHA1(unsigned char *out, const unsigned char *key, unsigned int keylen, const unsigned char *data, unsigned int datalen) {
    HMAC_SHA1_CTX ctx;
    HMAC_SHA1_Init(&ctx);
    HMAC_SHA1_UpdateKey(&ctx, key, keylen);
    HMAC_SHA1_EndKey(&ctx);
    HMAC_SHA1_StartMessage(&ctx);
    HMAC_SHA1_UpdateMessage(&ctx, data, datalen);
    HMAC_SHA1_EndMessage(out, &ctx);
    HMAC_SHA1_Done(&ctx);
}

#ifdef  __cplusplus
}
#endif

